module WeChatter
  module Models
    module Properties
      extend ::ActiveSupport::Concern

      included do
        delegate :id_name, to: :class
        delegate :property_names, to: :class

        def initialize(**args)
          args = ::ActiveSupport::HashWithIndifferentAccess.new(args)
          self.id = args.delete(id_name)
          property_names.each do |name|
            send("#{name}=", args[name.to_s.remove('_')])
          end
        end

        def properties
          property_names.prepend(id_name).map{|name|send(name)}
        end

        def to_json
          Yajl.dump(properties)
        end
      end

      module ClassMethods
        attr_accessor :id_name, :property_names

        def id(id_name)
          @id_name = id_name
          define_id_property(id_name)
        end

        def properties(*prop_names)
          @property_names = prop_names
          define_properties(prop_names)
        end

        private
        def define_id_property(id_name)
          define_id_reader id_name
          define_id_writer id_name
        end

        def define_properties(prop_names)
          prop_names.each do |name|
            define_prop_reader name
            define_prop_writer name
          end
        end

        def define_prop_reader(prop_name)
          attr_reader prop_name
          define_method("#{prop_name}?"){!!prop_name}
        end

        def define_id_reader(prop_name)
          define_prop_reader prop_name
          alias_method :id, prop_name
        end

        def define_prop_writer(prop_name)
          attr_writer prop_name
        end

        def define_id_writer(id_name)
          attr_writer id_name
          alias_method :id=, "#{id_name}="
        end
      end
    end
  end
end